package org.wattdepot.cli.commands;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import org.wattdepot.client.BadXmlException;
import org.wattdepot.client.MiscClientException;
import org.wattdepot.client.NotAuthorizedException;
import org.wattdepot.client.ResourceNotFoundException;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.resource.source.jaxb.Source;

/**
 * This class contains a command that generates a table where the first column 
 * contains fuel types and the second column is a comma-delimited list of 
 * (non-virtual) sources generating power using that fuel type.  It is used for
 * one of the CommandLineInterface's actual commands.
 *  
 * @author David Mau
 */
public class FuelTypesCommand implements WattDepotCliCommand {
  // Default client-server connection to use unless given one.
  private WattDepotClient client = new WattDepotClient(debug);

  /**
   * This constructor makes sure that the client really is connected to the server.
   * 
   * @param anotherClient Specifies if the user wants to use another WattDepot server
   * other than the default simulation one.
   */
  public FuelTypesCommand( String anotherClient ) {
    // If another client is provided
    if ( anotherClient != null ) {
      client = new WattDepotClient( anotherClient );
    }
    
    // Stop right away if we cannot contact server.
    if (!client.isHealthy()) {
      System.out.println("Failed to connect to " + client.getWattDepotUri());
      return;
    }
    // Indicate successful connection.
    //System.out.println("Connected to " + client.getWattDepotUri());
  }
  
  /**
   * The method returns a table in String form that lists the fuel types and
   * the non-virtual sources that generate power using that type.
   * Created by David Mau.
   * 
   * @param args A list of arguments given to this command
   * @return A String with the fuel types command output in it.
   */
  public String doCommand(List<String> args) {
    String output = "";
    // Check the size of the arguments passed to this command.
    // If the number of arguments is too large or too small,
    // return an error.
    if (args.size() > 1) {
      output = tooManyArguments;
      output = output.concat(cr);
      return output;
    }
    if (args.size() < 1) {
      output = missingArguments;
      output = output.concat(cr);
      return output;
    }
    
    // Create a list for all of the sources that the program will need to go through.
    ArrayList<Source> allSources = new ArrayList<Source>();
    
    // Place all non-virtual sources that the parent source links to into the list.
    try {
      // Get the source information from the client using the argument passed.
      Source parent = client.getSource( args.get(0));
      
      // Add the source to the list of fuel sources the program needs to go through.
      allSources.add( parent );
      
      int counter = 0;
        
      // Go through the list of uncheckedSources
      while ( counter < allSources.size() ) {
        
        // If the source is a virtual source,
        if ( allSources.get(counter).isVirtual() ) {
          
          // Get all sub-sources from the parent.
          List<String> children = allSources.get(counter).getSubSources().getHref();
          // Add them all as sources to the list.
          for ( String child : children ) {
            
            // Break the url up.
            String[] urlBreak = child.split("/");
            ArrayList<String> brokenUrl = new ArrayList<String>();
            for ( String url : urlBreak ) {
              brokenUrl.add( url );
            }
            // Figure out the last part of the url.
            int lastIndex = brokenUrl.size() - 1;
            
            // Get the source from the client.
            Source newAddition = client.getSource( brokenUrl.get(lastIndex) );
            // Add the child to the list.
            allSources.add(newAddition);
          }
          
          // Remove the virtual source from the list
          allSources.remove(counter);
        }
        // Otherwise, the source is non-virtual.
        else {
          // Move onto the next item on the list.
          counter++;
        }
      }
    }
    catch (NotAuthorizedException e) {
      output = notAuthorized;
      output = output.concat(e.toString());
      output = output.concat(cr);
      return output;
    }
    catch (ResourceNotFoundException e) {
      output = resourceNotFound;
      output = output.concat(e.toString());
      output = output.concat(cr);
      return output;
    }
    catch (BadXmlException e) {
      output = badXml;
      output = output.concat(e.toString());
      output = output.concat(cr);
      return output;
    }
    catch (MiscClientException e) {
      output = miscClient;
      output = output.concat(e.toString());
      output = output.concat(cr);
      return output;
    }
    
    // Create a Set to keep track of how many fuel types there are for this command.
    HashSet<String> fuelTypes = new HashSet<String>();
    // Go through the list of sources we need to go through.
    for ( Source source : allSources ) {
      // Add the fuel types into the set.
      fuelTypes.add( source.getProperty("fuelType") );
    }
    
    // Go through the Set of fuel types
    for ( String singleType : fuelTypes ) {
      boolean first = true;
      // Print the fuel type to the output.
      output = output.concat( singleType + " : " );
      
      int counter = 0;
      // Go through the list of sources we need to go through again.
      while ( counter < allSources.size() ) {
        // For each one, check if the fuel type matches.
        String sourceFuel = allSources.get(counter).getProperty("fuelType");
        if ( singleType.compareTo( sourceFuel ) == 0 ) {
          // If it does, print the source name to the output.
          // If it is the first, print with no comma
          if ( first ) {
            output = output.concat( allSources.get(counter).getName() );
            first = false;
          }
          else {
            // If it is not the first, print with a preceding comma.
            output = output.concat( "," + allSources.get(counter).getName() );
          }
          
          // Remove the item from the list so other fuel types won't go through it again.
          allSources.remove(counter);
        }
        // If the fuel type doesn't match, go onto the next item.
        else {
          counter++;
        }
      }
      
      // Add a newline after all sources get printed.
      output = output.concat(cr);
    }
    return output;
  }
}
